#include <gtk/gtk.h>
#include <gdk/gdk.h>
+#include <cogl/cogl.h>
+#include <meta/screen.h>
+#include <meta/meta-cursor-tracker.h>
+
#include "shell-recorder-src.h"
#include "shell-recorder.h"
#include <clutter/x11/clutter-x11.h>
-#include <X11/extensions/Xfixes.h>
#include <X11/extensions/XInput.h>
#include <X11/extensions/XInput2.h>
int pointer_x;
int pointer_y;
- gboolean have_xfixes;
- int xfixes_event_base;
-
int xinput_opcode;
GSettings *a11y_settings;
gboolean draw_cursor;
+ MetaCursorTracker *cursor_tracker;
cairo_surface_t *cursor_image;
+ guint8 *cursor_memory;
int cursor_hot_x;
int cursor_hot_y;
enum {
PROP_0,
+ PROP_SCREEN,
PROP_STAGE,
PROP_FRAMERATE,
PROP_PIPELINE,
if (recorder->cursor_image)
cairo_surface_destroy (recorder->cursor_image);
+ if (recorder->cursor_memory)
+ g_free (recorder->cursor_memory);
recorder_set_stage (recorder, NULL);
recorder_set_pipeline (recorder, NULL);
static void
recorder_fetch_cursor_image (ShellRecorder *recorder)
{
- XFixesCursorImage *cursor_image;
- guchar *data;
+ CoglTexture *texture;
+ int width, height;
int stride;
- int i, j;
-
- if (!recorder->have_xfixes)
- return;
-
- cursor_image = XFixesGetCursorImage (clutter_x11_get_default_display ());
- if (!cursor_image)
- return;
-
- recorder->cursor_hot_x = cursor_image->xhot;
- recorder->cursor_hot_y = cursor_image->yhot;
-
- recorder->cursor_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- cursor_image->width,
- cursor_image->height);
-
- /* The pixel data (in typical Xlib breakage) is longs even on
- * 64-bit platforms, so we have to data-convert there. For simplicity,
- * just do it always
- */
- data = cairo_image_surface_get_data (recorder->cursor_image);
- stride = cairo_image_surface_get_stride (recorder->cursor_image);
- for (i = 0; i < cursor_image->height; i++)
- for (j = 0; j < cursor_image->width; j++)
- *(guint32 *)(data + i * stride + 4 * j) = cursor_image->pixels[i * cursor_image->width + j];
-
- cairo_surface_mark_dirty (recorder->cursor_image);
+ guint8 *data;
- XFree (cursor_image);
+ texture = meta_cursor_tracker_get_sprite (recorder->cursor_tracker);
+ width = cogl_texture_get_width (texture);
+ height = cogl_texture_get_height (texture);
+ stride = 4 * width;
+ data = g_new (guint8, stride * height);
+ cogl_texture_get_data (texture, CLUTTER_CAIRO_FORMAT_ARGB32, stride, data);
+
+ /* FIXME: cairo-gl? */
+ recorder->cursor_image = cairo_image_surface_create_for_data (data,
+ CAIRO_FORMAT_ARGB32,
+ width, height,
+ stride);
+ recorder->cursor_memory = data;
}
/* Overlay the cursor image on the frame. We draw the cursor image
recorder_idle_redraw, recorder, NULL);
}
+static void
+on_cursor_changed (MetaCursorTracker *tracker,
+ ShellRecorder *recorder)
+{
+ if (recorder->cursor_image)
+ {
+ cairo_surface_destroy (recorder->cursor_image);
+ recorder->cursor_image = NULL;
+ }
+ if (recorder->cursor_memory)
+ {
+ g_free (recorder->cursor_memory);
+ recorder->cursor_memory = NULL;
+ }
+
+ recorder_queue_redraw (recorder);
+}
+
/* We use an event filter on the stage to get the XFixesCursorNotifyEvent
* and also to track cursor position (when the cursor is over the stage's
* input area); tracking cursor position here rather than with ClutterEvent
xev->xcookie.extension == recorder->xinput_opcode)
input_event = (XIEvent *) xev->xcookie.data;
- if (xev->xany.type == recorder->xfixes_event_base + XFixesCursorNotify)
- {
- XFixesCursorNotifyEvent *notify_event = (XFixesCursorNotifyEvent *)xev;
-
- if (notify_event->subtype == XFixesDisplayCursorNotify)
- {
- if (recorder->cursor_image)
- {
- cairo_surface_destroy (recorder->cursor_image);
- recorder->cursor_image = NULL;
- }
-
- recorder_queue_redraw (recorder);
- }
- }
- else if (input_event != NULL &&
- input_event->evtype == XI_Motion)
+ if (input_event != NULL &&
+ input_event->evtype == XI_Motion)
{
XIDeviceEvent *device_event = (XIDeviceEvent *) input_event;
if (device_event->deviceid == VIRTUAL_CORE_POINTER_ID)
recorder_update_size (recorder);
- recorder->have_xfixes = XFixesQueryExtension (clutter_x11_get_default_display (),
- &recorder->xfixes_event_base,
- &error_base);
- if (recorder->have_xfixes)
- XFixesSelectCursorInput (clutter_x11_get_default_display (),
- clutter_x11_get_stage_window (stage),
- XFixesDisplayCursorNotifyMask);
-
if (XQueryExtension (clutter_x11_get_default_display (),
"XInputExtension",
&recorder->xinput_opcode,
}
}
+static void
+recorder_set_screen (ShellRecorder *recorder,
+ MetaScreen *screen)
+{
+ MetaCursorTracker *tracker;
+
+ tracker = meta_cursor_tracker_get_for_screen (screen);
+
+ if (tracker == recorder->cursor_tracker)
+ return;
+
+ recorder->cursor_tracker = tracker;
+ g_signal_connect_object (tracker, "cursor-changed",
+ G_CALLBACK (on_cursor_changed), recorder, 0);
+}
+
static void
recorder_set_framerate (ShellRecorder *recorder,
int framerate)
switch (prop_id)
{
+ case PROP_SCREEN:
+ recorder_set_screen (recorder, g_value_get_object (value));
+ break;
case PROP_STAGE:
recorder_set_stage (recorder, g_value_get_object (value));
break;
gobject_class->get_property = shell_recorder_get_property;
gobject_class->set_property = shell_recorder_set_property;
+ g_object_class_install_property (gobject_class,
+ PROP_SCREEN,
+ g_param_spec_object ("screen",
+ "Screen",
+ "Screen to record",
+ META_TYPE_SCREEN,
+ G_PARAM_WRITABLE));
+
g_object_class_install_property (gobject_class,
PROP_STAGE,
g_param_spec_object ("stage",
+++ /dev/null
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-
-#define GST_USE_UNSTABLE_API
-#include "shell-recorder.h"
-#include <clutter/clutter.h>
-#include <gtk/gtk.h>
-#include <gst/gst.h>
-
-/* Very simple test of the ShellRecorder class; shows some text strings
- * moving around and records it.
- */
-static ShellRecorder *recorder = NULL;
-
-static gboolean
-stop_recording_timeout (ClutterActor *stage)
-{
- if (recorder)
- {
- shell_recorder_close (recorder);
-
- /* quit when the recorder finishes closing
- */
- g_object_weak_ref (G_OBJECT (recorder),
- (GWeakNotify)
- clutter_actor_destroy,
- stage);
-
- g_object_unref (recorder);
- }
- else
- {
- clutter_actor_destroy (stage);
- }
-
- return FALSE;
-}
-
-static void
-on_animation_completed (ClutterAnimation *animation,
- ClutterStage *stage)
-{
- g_timeout_add (1000, (GSourceFunc) stop_recording_timeout, stage);
-}
-
-static void
-on_stage_realized (ClutterActor *stage,
- gpointer data)
-{
- recorder = shell_recorder_new (CLUTTER_STAGE (stage));
- shell_recorder_set_file_template (recorder, "test-recorder.webm");
- shell_recorder_record (recorder, NULL);
-}
-
-int main (int argc, char **argv)
-{
- ClutterActor *stage;
- ClutterActor *text;
- ClutterAnimation *animation;
- ClutterColor red, green, blue;
-
- gtk_init (&argc, &argv);
- gst_init (&argc, &argv);
- if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
- return 1;
-
- clutter_color_from_string (&red, "red");
- clutter_color_from_string (&green, "green");
- clutter_color_from_string (&blue, "blue");
- stage = clutter_stage_new ();
- g_signal_connect (stage, "destroy", G_CALLBACK (clutter_main_quit), NULL);
-
- text = g_object_new (CLUTTER_TYPE_TEXT,
- "text", "Red",
- "font-name", "Sans 40px",
- "color", &red,
- NULL);
- clutter_actor_add_child (stage, text);
- animation = clutter_actor_animate (text,
- CLUTTER_EASE_IN_OUT_QUAD,
- 3000,
- "x", 320.0,
- "y", 240.0,
- NULL);
- g_signal_connect (animation, "completed",
- G_CALLBACK (on_animation_completed), stage);
-
- text = g_object_new (CLUTTER_TYPE_TEXT,
- "text", "Blue",
- "font-name", "Sans 40px",
- "color", &blue,
- "x", 640.0,
- "y", 0.0,
- NULL);
- clutter_actor_set_anchor_point_from_gravity (text, CLUTTER_GRAVITY_NORTH_EAST);
- clutter_actor_add_child (stage, text);
- animation = clutter_actor_animate (text,
- CLUTTER_EASE_IN_OUT_QUAD,
- 3000,
- "x", 320.0,
- "y", 240.0,
- NULL);
-
- text = g_object_new (CLUTTER_TYPE_TEXT,
- "text", "Green",
- "font-name", "Sans 40px",
- "color", &green,
- "x", 0.0,
- "y", 480.0,
- NULL);
- clutter_actor_set_anchor_point_from_gravity (text, CLUTTER_GRAVITY_SOUTH_WEST);
- clutter_actor_add_child (stage, text);
- animation = clutter_actor_animate (text,
- CLUTTER_EASE_IN_OUT_QUAD,
- 3000,
- "x", 320.0,
- "y", 240.0,
- NULL);
-
- g_signal_connect_after (stage, "realize",
- G_CALLBACK (on_stage_realized), NULL);
-
- clutter_actor_show (stage);
-
- clutter_main ();
-
- return 0;
-}